//
//  UDPSocket.cpp
//  MultiPlayer
//
//  Created by 星落之尘 on 2020/6/9.
//  Copyright © 2020 Tan. All rights reserved.
//

#include "UDPSocket.h"



int UDPSocket::Bind(const SocketAddress& inBindAddress)
{
    int error = bind(mSocket, &inBindAddress.mSockAddr, inBindAddress.GetSize());
    if (error != 0)
    {
        SocketUtil::ReportError("UDPSocket::Bind");
        return SocketUtil::GetLastError();
    }
    return NO_ERROR;
}


int UDPSocket::SendTo(const void *inToSend, int inLength, const SocketAddress &inToAddress) {
    int byteSendCount = sendto(mSocket, static_cast<const char*> (inToSend), inLength, 0, &inToAddress.mSockAddr, inToAddress.GetSize());
    if (byteSendCount <= 0)
    {
        SocketUtil::ReportError("UDPSocket::SendTo");
        return ~SocketUtil::GetLastError();
    }
    else
    {
        return byteSendCount;
    }
}

int UDPSocket::ReceiveFrom(void *inToReceive, int inMaxLegnth, SocketAddress &outFromAddress)
{
    socklen_t fromLength = outFromAddress.GetSize();
    int readByteCount =  recvfrom( mSocket,
                                    static_cast< char* >( inToReceive ),
                                    inMaxLegnth,
                                    0, &outFromAddress.mSockAddr, &fromLength );
    
    if (readByteCount >= 0) {
        return readByteCount;
    }
    else
    {
        int error = SocketUtil::GetLastError();
        if (error == WSAEWOULDBLOCK)
        {
            return 0;
        }
        else if ( error == WSAECONNRESET)
        {
            LOG("Connection reset from %s", outFromAddress.ToString().c_str());
            return -WSAECONNRESET;
        }
        else
        {
            SocketUtil::ReportError("UDPSocket::ReceiveFrom");
            return -error;
        }
    }
}


UDPSocket::~UDPSocket()
{
#if _WIN32
    closesocket( mSocket );
#else
    close( mSocket );
#endif
}


int UDPSocket::SetNonBlockingMode(bool inShouldBetNonBlocking)
{
#if _WIN32
    u_long arg = inShouldBetNonBlocking ? 1: 0
    int result = ioctlsocket( mSocket, FIONBIO, &arg);
#else
    
    int flags = fcntl(mSocket, F_GETFL, 0);
    flags = inShouldBetNonBlocking ? ( flags | O_NONBLOCK) : (flags | ~O_NONBLOCK);
    int result = fcntl(mSocket, F_SETFL, flags);
#endif
    
    if (result == SOCKET_ERROR)
    {
        SocketUtil::ReportError( "UDPSocket::SetNonBlockingMode" );
        return SocketUtil::GetLastError();
    } else {
        return NO_ERROR;
    }
}

